package com.java.design.spring.context.support;

import cn.hutool.core.util.ObjectUtil;
import com.java.design.spring.beans.BeanDefinition;
import com.java.design.spring.beans.MuTablePropertyValues;
import com.java.design.spring.beans.PropertyValue;
import com.java.design.spring.beans.factory.support.BeanDefinitionRegistry;
import com.java.design.spring.beans.factory.xml.XmlBeanDefinitionReader;
import com.java.design.spring.utils.TestUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Method;

/**
 * @author dgg
 * @date 2023/3/31 0:47
 * @description: IOC容器具体的子类
 * 用于加载类路径下的xml格式的配置文件
 */
public class ClassPathXmlApplicationContext extends AbstractApplicationContext {
    public ClassPathXmlApplicationContext(String configLocation) {
        this.configLocation = configLocation;
        beanDefinitionReader = new XmlBeanDefinitionReader();

        try {
            this.refresh();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Object getBean(String name) throws Exception {

        Object o = singletonobjects.get(name);
        if (ObjectUtil.isNotEmpty(o)) {
            return o;
        }
        //获取beanDefinition 对象
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
        BeanDefinition beanDefinition = registry.getBeanDefinition(name);
        String className = beanDefinition.getClassName();
        Class<?> aClass = Class.forName(className);
        Object beanObj = aClass.newInstance();
        //进行依赖注入
        MuTablePropertyValues propertyValues = beanDefinition.getPropertyValues();
        for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {
            String name1 = propertyValue.getName();
            String value = propertyValue.getValue();
            String ref = propertyValue.getRef();
            if (StringUtils.isNotBlank(ref)) {
                //获取依赖的bean对象
                Object bean = getBean(ref);
                //拼接方法名
                String setterMethodByFieldName = TestUtils.getSetterMethodByFieldName(name1);
                //获取方法对象
                Method[] methods = aClass.getMethods();
                for (Method method : methods) {
                    if (setterMethodByFieldName.equals(method.getName())) {
                        method.invoke(beanObj, bean);
                    }
                }
            }
            if (StringUtils.isNotBlank(value)) {
                String setterMethodByFieldName = TestUtils.getSetterMethodByFieldName(name1);
                Method method = aClass.getMethod(setterMethodByFieldName, String.class);
                method.invoke(beanObj, value);
            }
        }

        singletonobjects.put(name, beanObj);
        return beanObj;
    }

    @Override
    public <T> T getBean(String name, Class<? extends T> clazz) throws Exception {
        Object bean = getBean(name);
        if (ObjectUtil.isEmpty(bean)) {
            return null;
        }
        return clazz.cast(bean);
    }
}
